/*
 *
   gcc Stencil_Test.c -L. -lGLESv2 -lmingw32 -lSDL2_test -lSDL2main -lSDL2 -lSDL2_ttf && a 
   gcc Stencil_Test.c SDL_test_common.c -lm -lSDL2 -lSDL2_ttf && ./a.out && ./a.out
   gcc Stencil_Test.c -llibGLESv2 -lSDL2_test -lm -lmingw32 -lSDL2main -lSDL2   && a
   there is a bug in xp, only show red color full of the window.

   Copyright (r) 1997-2014 Sam Lantinga <slouken@libsdl.org>

   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
   arising from the use of this software.

   Permission is granted to anyone to use this software for any purpose,
   including commercial applications, and to alter it and redistribute it
   freely.
   */
#define PI 3.1415926535897932384626433832795f
#include "gles2base.h"
#include "SDL2/SDL.h"

int Init ( UserData *userData)
{
	GLbyte vShaderStr[] =  
		"attribute vec4 a_position;   \n"
		"void main()                  \n"
		"{                            \n"
		"   gl_Position = a_position; \n"
		"}                            \n";

	GLbyte fShaderStr[] =  
		"precision mediump float;  \n"
		"uniform vec4  u_color;    \n"
		"void main()               \n"
		"{                         \n"
		"  gl_FragColor = u_color; \n"
		"}                         \n";

	// Load the shaders and get a linked program object
	userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );

	// Get the attribute locations
	userData->positionLoc = ctx.glGetAttribLocation ( userData->programObject, "a_position" );

	// Get the sampler location
	userData->colorLoc = ctx.glGetUniformLocation ( userData->programObject, "u_color" );

	// Set the clear color
	ctx.glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );

	// Set the stencil clear value
	ctx.glClearStencil ( 0x1 );

	// Set the depth clear value
	ctx.glClearDepthf( 0.75f );

	// Enable the depth and stencil tests
	ctx.glEnable( GL_DEPTH_TEST );
	ctx.glEnable( GL_STENCIL_TEST );

	return 1;
}

///
// Initialize the stencil buffer values, and then use those
//   values to control rendering
//
void Draw ( UserData *userData)
{
	int  i;
	GLfloat vVertices[] = { 
		-0.75f,  0.25f,  0.50f, // Quad #0
		-0.25f,  0.25f,  0.50f,
		-0.25f,  0.75f,  0.50f,
		-0.75f,  0.75f,  0.50f,
		0.25f,  0.25f,  0.90f, // Quad #1
		0.75f,  0.25f,  0.90f,
		0.75f,  0.75f,  0.90f,
		0.25f,  0.75f,  0.90f,
		-0.75f, -0.75f,  0.50f, // Quad #2
		-0.25f, -0.75f,  0.50f,
		-0.25f, -0.25f,  0.50f,
		-0.75f, -0.25f,  0.50f,
		0.25f, -0.75f,  0.50f, // Quad #3
		0.75f, -0.75f,  0.50f,
		0.75f, -0.25f,  0.50f,
		0.25f, -0.25f,  0.50f,
		-1.00f, -1.00f,  0.00f, // Big Quad
		1.00f, -1.00f,  0.00f,
		1.00f,  1.00f,  0.00f,
		-1.00f,  1.00f,  0.00f
	};

	GLubyte indices[][6] = { 
		{  0,  1,  2,  0,  2,  3 }, // Quad #0
		{  4,  5,  6,  4,  6,  7 }, // Quad #1
		{  8,  9, 10,  8, 10, 11 }, // Quad #2
		{ 12, 13, 14, 12, 14, 15 }, // Quad #3
		{ 16, 17, 18, 16, 18, 19 }  // Big Quad
	};

#define NumTests  4
	GLfloat  colors[NumTests][4] = { 
		{ 1.0f, 0.0f, 0.0f, 1.0f },
		{ 0.0f, 1.0f, 0.0f, 1.0f },
		{ 0.0f, 0.0f, 1.0f, 1.0f },
		{ 1.0f, 1.0f, 0.0f, 0.0f }
	};

	GLint   numStencilBits;
	GLuint  stencilValues[NumTests] = { 
		0x7, // Result of test 0
		0x0, // Result of test 1
		0x2, // Result of test 2
		0xff // Result of test 3.  We need to fill this
			//  value in a run-time
	};

	// Set the viewport
	ctx.glViewport ( 0, 0, state->window_w, state->window_h);

	// Clear the color, depth, and stencil buffers.  At this
	//   point, the stencil buffer will be 0x1 for all pixels
	ctx.glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );

	// Use the program object
	ctx.glUseProgram ( userData->programObject );

	// Load the vertex position
	ctx.glVertexAttribPointer ( userData->positionLoc, 3, GL_FLOAT, 
			GL_FALSE, 0, vVertices );

	ctx.glEnableVertexAttribArray ( userData->positionLoc );

	// Test 0:
	//
	// Initialize upper-left region.  In this case, the
	//   stencil-buffer values will be replaced because the
	//   stencil test for the rendered pixels will fail the
	//   stencil test, which is
	//
	//        ref   mask   stencil  mask
	//      ( 0x7 & 0x3 ) < ( 0x1 & 0x7 )
	//
	//   The value in the stencil buffer for these pixels will
	//   be 0x7.
	//
	ctx.glStencilFunc( GL_LESS, 0x7, 0x3 );
	ctx.glStencilOp( GL_REPLACE, GL_DECR, GL_DECR );
//#define GL_TRIANGLES GL_LINE_LOOP
	ctx.glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[0] );

	// Test 1:
	//
	// Initialize the upper-right region.  Here, we'll decrement
	//   the stencil-buffer values where the stencil test passes
	//   but the depth test fails.  The stencil test is
	//
	//        ref  mask    stencil  mask
	//      ( 0x3 & 0x3 ) > ( 0x1 & 0x3 )
	//
	//    but where the geometry fails the depth test.  The
	//    stencil values for these pixels will be 0x0.
	//
	ctx.glStencilFunc( GL_GREATER, 0x3, 0x3 );
	ctx.glStencilOp( GL_KEEP, GL_DECR, GL_KEEP );
	ctx.glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[1] );

	// Test 2:
	//
	// Initialize the lower-left region.  Here we'll increment 
	//   (with saturation) the stencil value where both the
	//   stencil and depth tests pass.  The stencil test for
	//   these pixels will be
	//
	//        ref  mask     stencil  mask
	//      ( 0x1 & 0x3 ) == ( 0x1 & 0x3 )
	//
	//   The stencil values for these pixels will be 0x2.
	//
	ctx.glStencilFunc( GL_EQUAL, 0x1, 0x3 );
	ctx.glStencilOp( GL_KEEP, GL_INCR, GL_INCR );
	ctx.glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[2] );

	// Test 3:
	//
	// Finally, initialize the lower-right region.  We'll invert
	//   the stencil value where the stencil tests fails.  The
	//   stencil test for these pixels will be
	//
	//        ref   mask    stencil  mask
	//      ( 0x2 & 0x1 ) == ( 0x1 & 0x1 )
	//
	//   The stencil value here will be set to ~((2^s-1) & 0x1),
	//   (with the 0x1 being from the stencil clear value),
	//   where 's' is the number of bits in the stencil buffer
	//
	ctx.glStencilFunc( GL_EQUAL, 0x2, 0x1 );
	ctx.glStencilOp( GL_INVERT, GL_KEEP, GL_KEEP );
	ctx.glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[3] );

	// Since we don't know at compile time how many stecil bits are present,
	//   we'll query, and update the value correct value in the
	//   stencilValues arrays for the fourth tests.  We'll use this value
	//   later in rendering.
	ctx.glGetIntegerv( GL_STENCIL_BITS, &numStencilBits );

	stencilValues[3] = ~(((1 << numStencilBits) - 1) & 0x1) & 0xff;

	// Use the stencil buffer for controlling where rendering will
	//   occur.  We diable writing to the stencil buffer so we
	//   can test against them without modifying the values we
	//   generated.
	ctx.glStencilMask( 0x0 );

	for ( i = 0; i < NumTests; ++i )
	{
		ctx.glStencilFunc( GL_EQUAL, stencilValues[i], 0xff );
		ctx.glUniform4fv( userData->colorLoc, 1, colors[i] );
		ctx.glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[4] );
	}
	/*eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );*/
}

